﻿using Insesoft.Entities;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace InseSoft.Tests.Unit.Entities
{
    [TestClass]
    public class CotizadorTest
    {
        [TestMethod]
        public void AgregarPorcentaje()
        {
            const decimal impuesto = 13;
            const decimal monto = 10;
            const decimal expectedResult = 11.3m;

            var cotizacion = new Cotizacion();
            var instance = new Cotizador(cotizacion);

            var result = instance.AgregarPorcentaje(monto, impuesto);

            Assert.AreEqual(expectedResult, result);
        }

        [TestMethod]
        public void CalcularRendimientos_SinDesperdicio_RendimientoExacto()
        {
            var material = new Material { Base = 10, Altura = 20 };
            var cotizacion = new Cotizacion { Base = 1, Altura = 2, Material = material };
            var instance = new Cotizador(cotizacion);

            instance.CalcularRendimientos();

            Assert.AreEqual(100, cotizacion.Rendimiento);
        }

        [TestMethod]
        public void CalcularRendimientos_ConDesperdicio_RendimientoRedondeado()
        {
            var material = new Material { Base = 10, Altura = 20 };
            var cotizacion = new Cotizacion { Base = 1, Altura = 3, Material = material };
            var instance = new Cotizador(cotizacion);

            instance.CalcularRendimientos();

            Assert.AreEqual(60, cotizacion.Rendimiento);
        }

        [TestMethod]
        public void CalcularRendimientos_SinDesperdicio_LargoYAnchoExacto()
        {
            var material = new Material { Base = 10, Altura = 20 };
            var cotizacion = new Cotizacion { Base = 1, Altura = 2, Material = material, Cantidad = 100 };
            var instance = new Cotizador(cotizacion);

            instance.CalcularRendimientos();

            Assert.AreEqual(10, cotizacion.DivLargo);
            Assert.AreEqual(10, cotizacion.DivAncho);
            AssertEqualDecimal(1, cotizacion.Laminas);
        }

        [TestMethod]
        public void CalcularRendimientos_ConDesperdicio_LargoYAnchoRedondeado()
        {
            var material = new Material { Base = 10, Altura = 20 };
            var cotizacion = new Cotizacion { Base = 1, Altura = 3, Material = material, Cantidad = 100 };
            var instance = new Cotizador(cotizacion);

            instance.CalcularRendimientos();

            AssertEqualDecimal(6.66m, cotizacion.DivLargo);
            AssertEqualDecimal(10, cotizacion.DivAncho);
            AssertEqualDecimal(1.66m, cotizacion.Laminas);
        }

        [TestMethod]
        public void CalcularRendimientos_OrientacionInvertida_LargoYAnchoRedondeado()
        {
            var material = new Material { Base = 10, Altura = 30 };
            var cotizacion = new Cotizacion { Base = 3, Altura = 5, Material = material, Cantidad = 100 };
            var instance = new Cotizador(cotizacion);

            instance.CalcularRendimientos();

            AssertEqualDecimal(2, cotizacion.DivLargo);
            AssertEqualDecimal(10, cotizacion.DivAncho);
            AssertEqualDecimal(5, cotizacion.Laminas);
        }

        [TestMethod]
        public void CalcularPrecioMaterial()
        {
            const decimal impuesto = 10m;
            var material = new Material { CostoInventario = 100 };
            var cotizacion = new Cotizacion { Material = material, Laminas = 5 };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioMaterial(impuesto);

            Assert.AreEqual(550, result);
        }

        [TestMethod]
        public void CalcularPrecioTintas()
        {
            const decimal precioTinta = 10m;
            var cotizacion = new Cotizacion { Altura = 10, Base = 20, Cubrimiento = 2, Cantidad = 5 };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioTintas(precioTinta);

            Assert.AreEqual(200, result);
        }

        [TestMethod]
        public void CalcularPrecioArte_TintasMenora1_RetornaPrecioArte()
        {
            const decimal precioArte = 10m;
            var cotizacion = new Cotizacion { Tintas = 0.5m };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioArte(precioArte);

            Assert.AreEqual(10, result);
        }

        [TestMethod]
        public void CalcularPrecioArte_TintasMayora1_RetornaPrecioArtePorTintas()
        {
            const decimal precioArte = 10m;
            var cotizacion = new Cotizacion { Tintas = 5 };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioArte(precioArte);

            Assert.AreEqual(50, result);
        }

        [TestMethod]
        public void CalcularPrecioPositivo_ResultadoMayorA2000_RetornaMultiplicacion()
        {
            const decimal precioPositivo = 10m;
            var cotizacion = new Cotizacion { Base = 10, Altura = 10, Montaje = 2, Tintas = 2 };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioPositivo(precioPositivo);

            Assert.AreEqual(4000, result);
        }

        [TestMethod]
        public void CalcularPrecioPositivo_ResultadoMenorA2000_Retorna2000()
        {
            const decimal precioPositivo = 10m;
            const decimal minPrecioPositivo = 2000m;
            var cotizacion = new Cotizacion { Base = 1, Altura = 1, Montaje = 1, Tintas = 1 };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioPositivo(precioPositivo);

            Assert.AreEqual(minPrecioPositivo, result);
        }

        [TestMethod]
        public void CalcularPrecioMolde_TintasMenora1_RetornaPrecioMolde()
        {
            const decimal precioMolde = 10m;
            var cotizacion = new Cotizacion { Tintas = 0.5m };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioMolde(precioMolde);

            Assert.AreEqual(10, result);
        }

        [TestMethod]
        public void CalcularPrecioMolde_TintasMayora1_RetornaPrecioMoldePorTintas()
        {
            const decimal precioMolde = 10m;
            var cotizacion = new Cotizacion { Tintas = 5 };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioMolde(precioMolde);

            Assert.AreEqual(50, result);
        }

        [TestMethod]
        public void CalcularPrecioSolvente_TintasMenora1_RetornaPrecioSolvente()
        {
            const decimal precioSolvente = 10m;
            var cotizacion = new Cotizacion { Tintas = 0.5m };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioSolvente(precioSolvente);

            Assert.AreEqual(10, result);
        }

        [TestMethod]
        public void CalcularPrecioSolvente_TintasMayora1_RetornaPrecioSolventePorTintas()
        {
            const decimal precioSolvente = 10m;
            var cotizacion = new Cotizacion { Tintas = 5 };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioSolvente(precioSolvente);

            Assert.AreEqual(50, result);
        }

        [TestMethod]
        public void CalcularPrecioCorte_PrecioCorteMenorA1_RetornaPrecioCorte()
        {
            const decimal precioCorte = 10m;
            var cotizacion = new Cotizacion { Cantidad = 100 };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioCorte(precioCorte);

            Assert.AreEqual(10, result);
        }

        [TestMethod]
        public void CalcularPrecioCorte_PrecioCorteMayorA1_RetornaMultiplicacion()
        {
            const decimal precioCorte = 10m;
            var cotizacion = new Cotizacion { Cantidad = 5000 };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioCorte(precioCorte);

            Assert.AreEqual(50, result);
        }

        [TestMethod]
        public void CalcularPrecioImpresion_MenorHoraImpresion_HoraImpresion()
        {
            var precio = new Precio { Velocidad = 10, HoraImpresion = 1000 };
            var cotizacion = new Cotizacion
            {
                Cantidad = 10,
                Montaje = 10,
                Tintas = 2
            };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioImpresion(precio);

            Assert.AreEqual(1000, result);
        }

        [TestMethod]
        public void CalcularPrecioImpresion_MayorHoraImpresion_HoraImpresion()
        {
            var precio = new Precio { Velocidad = 1, HoraImpresion = 100 };
            var cotizacion = new Cotizacion
            {
                Cantidad = 10,
                Montaje = 10,
                Tintas = 2
            };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioImpresion(precio);

            Assert.AreEqual(200, result);
        }

        [TestMethod]
        public void CalcularSubTotal()
        {
            var cotizacion = new Cotizacion
            {
                PrecioMaterial = 1,
                PrecioTintas = 2,
                PrecioArte = 3,
                PrecioPositivo = 4,
                PrecioMolde = 5,
                PrecioSolvente = 6,
                PrecioCorte = 7,
                PrecioImpresion = 8,
                Troquel = 9,
                Doblez = 10,
                Cuatricromia = 11,
                Otro = 12.567m
            };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularSubtotal();

            Assert.AreEqual(78.57m, result);
        }

        [TestMethod]
        public void CalcularTotalCol_SinEvento_UtilidadAgregada()
        {   
            var cotizacion = new Cotizacion
            {
                Subtotal = 100,
                Empresa = new Empresa {Utilidad = 20},
                Evento = false
            };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularTotalCol();

            Assert.AreEqual(120, result);
        }

        [TestMethod]
        public void CalcularTotalCol_ConEvento_UtilidadYEventoAgregados()
        {   
            var cotizacion = new Cotizacion
            {
                Subtotal = 100,
                Empresa = new Empresa { Utilidad = 20 },
                Evento = true,
                PorcEvento = 10
            };
            const decimal expectedResult = 132;
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularTotalCol();

            Assert.AreEqual(expectedResult, result);
        }
        
        [TestMethod]
        public void CalcularTotalUsd()
        {
            const decimal totalCol = 5000;
            var cotizacion = new Cotizacion
            {
                TotalCol = totalCol,
                TipoCambio = new TipoCambio { Monto = 500 }
            };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularTotalUsd();

            Assert.AreEqual(10, result);
        }

        [TestMethod]
        public void CalcularPrecioUnitario()
        {
            var cotizacion = new Cotizacion
            {
                TotalCol = 100,
                Cantidad = 5
            };
            var instance = new Cotizador(cotizacion);

            var result = instance.CalcularPrecioUnitario();

            Assert.AreEqual(20, result);
        }

        #region Helpers

        private static void AssertEqualDecimal(decimal expected, decimal actual)
        {
            const float delta = 0.01f;
            var expectedFloat = (float)expected;
            var actualFloat = (float)actual;

            Assert.AreEqual(expectedFloat, actualFloat, delta);
        }

        #endregion
    }
}
